home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World's Largest Collection of Windows Software
/
The World's Largest Collection of Windows Software - Disc 1.iso
/
connect
/
_j2
/
wsmtpd16
/
net.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-09
|
17KB
|
635 lines
/* NET.C - Network window procedure for WSMTPSRV
- WinSock V1.1 required
Author: Ian Blenke
Ian Blenke cannot be held responsible for damages, expressed or implied, for
the use of this software. No commercial use can be made of this product
without the consent of the author. No profit of any kind can be made on the
sale or distribution of this program. If you wish to distribute this program
with other samples of WinSock programming, you must first contact the author
so that he can keep accurate records of its usage. If you write any programs
based on this source code, you may not sell them for any profit without the
written consent of the author. If you incorporate this source code into a
public domain program, all the author requires is a notification that "part
of the code was written by Ian Blenke" and some form of notification that
his name was used in the public domain software distribution. This does not
represent a contract on the part of the author. If any issues cannot clearly
be resolved by reading this text, immediately contact the author.
If you have any bug reports and/or source patches... By all means, tell me! I
would be glad to help keep this code up to date. Do not, however, modify this
source in any way and re-distribute it without the author's knowledge. This
would constitute something not-good.
I don't like such agreements, but in today's world of lawyers and lawbreakers
I have little other choice. Enjoy!
*/
#ifndef NET_C
#define NET_C
#include "Net.H"
#include "Dialogs.h"
#include <Time.h> // DOS Time functions for netGetTimeAndDate()
/* BOOL netInit(void);
Purpose: To initialize the network window
Given: Nothing.
Returns: TRUE if an error occured.
*/
BOOL netInit(void)
{
WNDCLASS wndclass;
SOCKADDR_IN saMain;
LPSERVENT lpseServEnt;
LPHOSTENT lpheHostEnt;
BOOL bDebug;
if(gethostname((LPSTR)szLocalHostName,
sizeof(szLocalHostName)) == SOCKET_ERROR)
{
// We need SOME valid name - make it "Unknown"
lstrcpy((LPSTR)szLocalHostName, (LPSTR)STRING_UNKNOWN);
}
else
{
lpheHostEnt=gethostbyname((LPSTR)szLocalHostName);
if(lpheHostEnt!=NULL)
{
lstrcpy((LPSTR)szLocalHostName, lpheHostEnt->h_name);
}
}
lstrcpy((LPSTR)szNetworkClass, (LPSTR)CLASS_NETWORK);
wndclass.style = 0;
wndclass.lpfnWndProc = (WNDPROC)NetProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInst;
wndclass.hIcon = NULL;
wndclass.hCursor = NULL;
wndclass.hbrBackground = NULL;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = (LPSTR)szNetworkClass;
if(!RegisterClass(&wndclass))
{
return(TRUE);
}
// Create the main "invisible" network window
hWndMain=CreateWindow((LPSTR)szNetworkClass,
(LPSTR)"",
WS_CHILD,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
hWndDlg, NULL, hInst, NULL);
if(!hWndMain)
{
UnregisterClass((LPSTR)szNetworkClass, hInst);
return(TRUE);
}
sSocketMain=socket(AF_INET, SOCK_STREAM, 0);
if(sSocketMain==SOCKET_ERROR)
{
netError();
DestroyWindow(hWndMain);
UnregisterClass((LPSTR)szNetworkClass, hInst);
return(TRUE);
}
lpseServEnt=getservbyname((LPSTR)SMTP_NAME, NULL);
if(lpseServEnt==NULL)
{
saMain.sin_port=htons(SMTP_PORT);
}
else
{
saMain.sin_port=lpseServEnt->s_port;
}
saMain.sin_family=AF_INET; // Address Family type Internet
saMain.sin_addr.s_addr=0; // Bind to local host
if(bind(sSocketMain, (LPSOCKADDR)&saMain,
sizeof(saMain))==SOCKET_ERROR)
{
netError();
DestroyWindow(hWndMain);
closesocket(sSocketMain);
UnregisterClass((LPSTR)szNetworkClass, hInst);
return(TRUE);
}
if(listen(sSocketMain, MAXCLIENTS)==SOCKET_ERROR)
{
netError();
DestroyWindow(hWndMain);
closesocket(sSocketMain);
UnregisterClass((LPSTR)szNetworkClass, hInst);
return(TRUE);
}
// Make the main socket non-blocking, and set up
// the connection message.
if(WSAAsyncSelect(sSocketMain, hWndMain, NET_ACTIVITY,
FD_READ | FD_WRITE | FD_ACCEPT | FD_CLOSE) == SOCKET_ERROR)
{
netError();
DestroyWindow(hWndMain);
closesocket(sSocketMain);
UnregisterClass((LPSTR)szNetworkClass, hInst);
return(TRUE);
}
bDebug=TRUE;
setsockopt(sSocketMain,
SOL_SOCKET, SO_DEBUG, (char FAR *)&bDebug,
sizeof(bDebug));
setsockopt(sSocketMain,
IPPROTO_TCP, SO_DEBUG, (char FAR *)&bDebug,
sizeof(bDebug));
// ALL sockets are accounted for with structures
// Even the main one - to get the NetProc to work right.
smtpAddClient(sSocketMain);
return(FALSE);
} /* netInit() */
/* void netError(void);
Purpose: To tell the user something broke.
Given: Nothing.
Returns: Nothing.
Uses: netErrorTable, WSAGetLastError(), smtpError()
*/
void netError(void)
{
int iError;
int iIndex;
iIndex=0;
iError=WSAGetLastError();
if((iError==WSAEWOULDBLOCK)||
(iError==WSAENOTCONN) ||
(iError==WSANO_DATA)) // Why does v1.09beta tell me this?
return;
while(netErrorTable[iIndex].iError!=0)
{
if(netErrorTable[iIndex].iError==iError)
{
smtpError(netErrorTable[iIndex].iResourceID);
return;
}
iIndex++;
}
return;
} /* netError */
/* void netClose(void);
Purpose: To close the network portion of WSMTPSRV
Given: Nothing.
Returns: Nothing.
*/
void netClose(void)
{
if(hWndMain)
{
smtpDestroyClient(smtpClientsHead);
smtpClientsHead=NULL;
DestroyWindow(hWndMain);
UnregisterClass((LPCSTR)szNetworkClass, hInst);
hWndMain=0;
}
WSACleanup();
return;
} /* netClose */
/* BOOL CALLBACK NetProc(HWND, UINT, WPARAM, LPARAM);
Purpose: To handle all Windows Sockets messages.
Given: Standard CALLBACK args.
Returns: FALSE if we handled it.
*/
LRESULT CALLBACK NetProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
// First thing we do is get the connection's window
LPSMTPCLIENT lpClient;
SOCKET sSocket;
#ifdef USE_TITLE
char szTitle[MAXLINE];
#endif /* USE_TITLE */
int iAddrSize;
SOCKADDR_IN saPeer;
LPSOCKADDR_IN lpsaHostAddr;
LPHOSTENT lpheHostEnt;
char szTime[40];
if(wParam!=0) lpClient=smtpSocketToClient((SOCKET)wParam);
else lpClient=NULL;
if(lpClient) // If it isn't a Client message - ignore it
{
switch(Msg)
{
case NET_ACTIVITY:
{
// This is the handler for the main network window
switch(WSAGETSELECTEVENT(lParam))
{
case FD_ACCEPT:
{
// Get a pending accept
iAddrSize=sizeof(SOCKADDR_IN);
sSocket=accept(sSocketMain,
(LPSOCKADDR)&saPeer,
(int FAR *)&iAddrSize);
if(sSocket==INVALID_SOCKET) return(FALSE);
// Allocate socket specific data
lpClient=smtpAddClient(sSocket);
if(!lpClient) return(FALSE);
// Remember the connected Peer's address
lpClient->saPeer=saPeer;
// Get the Peer's Name asyncronously
lpsaHostAddr=(LPSOCKADDR_IN)&(lpClient->saPeer);
lpheHostEnt= gethostbyaddr((LPSTR)&(lpsaHostAddr->sin_addr.s_addr),
4, PF_INET);
if(lpheHostEnt==NULL)
{ // Ah HA! No sneaking in!
lstrcpy((LPSTR)lpClient->szPeer,
inet_ntoa(lpsaHostAddr->sin_addr));
}
else
{
lstrcpy((LPSTR)lpClient->szPeer,
(LPSTR)(lpheHostEnt->h_name));
}
smtpLog(LOG_HIGH | LOG_TIME, LOG_CONNECT_S,
(LPSTR)lpClient->szPeer);
netGetTimeAndDate((LPSTR)szTime, sizeof(szTime));
/* Set the window title (for debugging) */
#ifdef USE_TITLE
if(iLogLevel==LOG_HIGH)
{
wsprintf((LPSTR)szTitle, "WSMTPD - Connect: from %s:%d",
(LPSTR)lpClient->szPeer,
lpClient->saPeer.sin_port);
SetWindowText(hWndDlg, (LPSTR)szTitle);
}
#endif /* USE_TITLE */
smtpSendMessage(lpClient, 220, MSG_I_AM_S_S,
(LPSTR)szLocalHostName,
(LPSTR)szTime);
// Not all stacks support this yet.
/* if(WSAAsyncGetHostByAddr(hWnd, NET_NAME,
(LPSTR)&(lpsaHostAddr->sin_addr.s_addr),
4, PF_INET,
(LPSTR)lpClient->hePeer,
MAXGETHOSTSTRUCT) != 0)
{
return(FALSE);
} /**/
// Make sure that the name can be found
netError();
PostMessage(hWnd, NET_NAME, 0, WSAMAKEASYNCREPLY(0 ,1));
return(FALSE);
}
// WinSock received something for us
case FD_READ:
{
int iError;
// FIFO log it
iError=netReceiveData(lpClient);
if(iError==0)
{ // It closed!?!
smtpDestroyClient(lpClient);
return(FALSE);
}
else if(iError==SOCKET_ERROR)
{ // Miscellaneous Error
netError();
return(FALSE);
}
// Call the server routines
(void)smtpServer(lpClient);
// We handled the event, return FALSE
return(FALSE);
}
break; /* FD_READ */
// WinSock is ready to send
case FD_WRITE:
{ // FIFO log it
if(netSendData(lpClient)==SOCKET_ERROR)
{
netError();
}
return(FALSE);
}
break;
// The MAIN accepting network window was closed!!!
case FD_CLOSE:
{ // This DOESNT work. And a good thing too..
//smtpSendMessage(lpClient, 221, MSG_GOODBYE_S,
// (LPSTR)szLocalHostName);
/* Set the window title (for debugging) */
#ifdef USE_TITLE
if(iLogLevel==LOG_HIGH)
{
wsprintf((LPSTR)szTitle, "WSMTPD - %s disconnected from port %d",
(LPSTR)lpClient->szPeer,
lpClient->saPeer.sin_port);
SetWindowText(hWndDlg, (LPSTR)szTitle);
}
#endif /* USE_TITLE */
// Hasta la Vista, Baby
smtpDestroyClient(lpClient);
return(FALSE);
}
break;
// Shouldn't get to here!!!
default:
{
netError();
return(FALSE);
}
}
} /* NET_ACCEPT */
break;
// Get the peer's name - No spoofing allowed in this server!
// gethostbyname() doesn't seem to block much anyway
// so it's a decent compromise.
/* case NET_NAME:
{
DEBUGIT("NET_NAME Event!");
if(WSAGETASYNCERROR(lParam))
{
lstrcpy((LPSTR)lpClient->szPeer,
(LPSTR)STRING_UNKNOWN);
}
else // We found a name!!!!
{
lstrcpy((LPSTR)lpClient->szPeer,
(LPSTR)((HOSTENT*)(lpClient->hePeer))->h_name);
}
smtpLog(LOG_CONNECT_S, (LPSTR)lpClient->szPeer);
}
break; /**/
} /* Msg*/
} /* if(index) */
switch(Msg)
{
case WM_CLOSE:
{ // A WSACleanup() here, and a WSACleanup() there....
smtpDestroyClient(smtpClientsHead);
smtpClientsHead=NULL;
WSACleanup();
} break;
default:
{
// Something has to handle the other messages!
return(DefWindowProc(hWnd, Msg, wParam, lParam));
}
}
} /* NetProc() */
/* int netGetTimeAndDate(LPSTR, int);
Purpose: To format the current system time/data into a passed
buffer.
Doesn't formats the output to what other SMTP servers
report - uses the ctime() call.
Given: String buffer pointer, and size of the buffer
Returns: TRUE if an error occurs, false otherwise
Notes: Version 1.0 uses DOS time functions. The Windows ones
are undocumented.
*/
BOOL netGetTimeAndDate(LPSTR lpLine, int iLine)
{
struct tm tmClock;
time_t tClock;
LPSTR lpSysTime;
char szTemp[256];
time(&tClock);
tmClock=*localtime(&tClock);
if(!strftime(szTemp, sizeof(szTemp), "%a, %d %b %y %H:%M:%S %z",
&tmClock))
{
lstrcpy((LPSTR)szTemp, (LPSTR)asctime(&tmClock));
szTemp[lstrlen((LPSTR)szTemp)-1]='\0';
};
if(lstrlen((LPSTR)szTemp)>iLine)
{
szTemp[iLine]='\0';
}
lstrcpy(lpLine, (LPSTR)szTemp);
return(FALSE);
} /* netGetTimeAndDate() */
/* int netSendData(int);
Purpose: To send data in the appropriate FIFO buffer
Sends data, and updates the pointers to what
was actually sent.
Given: Client index;
Returns: Same as send()
Notes: If smtpSendString finds stop=start, then he
should flag the fact that the buffer WAS
empty, and then call this routine to set up
sending messages!!!
*/
int netSendData(LPSMTPCLIENT lpClient)
{
LPSTR lpBuffer;
LPSTR lpLine;
int fifoStart;
int fifoStop;
int fifoWalker;
int iDest;
int iCount;
int sSocket;
#ifdef USE_TITLE
char szTitle[MAXLINE];
#endif /* USE_TITLE */
sSocket = lpClient->sSocket;
if(!lpClient) return(SOCKET_ERROR);
lpLine = (LPSTR)szMainBuffer;
/* Make things easier to deal with */
lpBuffer=lpClient->lpOutputBuffer;
fifoStart=lpClient->fifoOutputStart;
fifoWalker=fifoStart;
fifoStop=lpClient->fifoOutputStop;
if(fifoStart==fifoStop)
{
return(0);
}
/* Keep trying to send until buffer
is empty, or WSAEWOULDBLOCK */
// do
// {
iDest=0;
while(fifoWalker!=fifoStop)
{
lpLine[iDest]=lpBuffer[fifoWalker];
fifoWalker=(fifoWalker+1)%MAXSNDBUFF;
iDest++;
}
iCount=send(sSocket, lpLine,
iDest, 0);
if(iCount==SOCKET_ERROR)
{
return(iCount);
}
fifoWalker=(fifoStart+iCount)%MAXSNDBUFF;
lpClient->fifoOutputStart=fifoWalker;
/* Set the window title (for debugging) */
#ifdef USE_TITLE
if(iLogLevel==LOG_HIGH)
{
wsprintf((LPSTR)szTitle, "WSMTPD - Sent: %d bytes to %s:%u",
iCount,
(LPSTR)lpClient->szPeer,
lpClient->saPeer.sin_port);
SetWindowText(hWndDlg, (LPSTR)szTitle);
}
#endif /* USE_TITLE */
// iDest -= iCount;
// } while(iDest!=0);
return(iCount);
} /* netSendData */
/* int netRecieveData(int);
Purpose: To receive data from WinSock into FIFOs
Updates the fifoStop pointer to the end of the
new data.
If no data is waiting, or there is no more room
in the buffer, this routine returns like recv().
Given: Client index.
Returns: same as recv();
*/
int netReceiveData(LPSMTPCLIENT lpClient)
{
LPSTR lpBuffer;
LPSTR lpLine;
int fifoStart;
int fifoStop;
int fifoWalker;
int iMax;
int iDest;
int iCount;
int sSocket;
#ifdef USE_TITLE
char szTitle[MAXLINE];
#endif /* USE_TITLE */
sSocket = lpClient->sSocket;
lpLine = (LPSTR)szMainBuffer;
iMax=lpClient->iInputSize;
fifoStart=lpClient->fifoInputStart;
fifoStop=lpClient->fifoInputStop;
// Calculate the room we have ready
// szMainBuffer can be a bottleneck if the Receive buffer is big
if(fifoStop<fifoStart) iDest=min( (fifoStart-fifoStop),
sizeof(szMainBuffer) );
else if(fifoStart<=fifoStop) iDest=min( (iMax-fifoStop+fifoStart),
sizeof(szMainBuffer) );
// The min() hack was so that we don't get more data than we
// are ready to handle.
lpBuffer=lpClient->lpInputBuffer;
/* There is room at the end! Copy it in! */
/* Tell winsock to release it first, tho */
iCount=recv(sSocket, lpLine,
iDest, 0);
/* Set the window title (for debugging) */
#ifdef USE_TITLE
if(iLogLevel==LOG_HIGH)
{
if(iCount!=SOCKET_ERROR)
{
wsprintf((LPSTR)szTitle, "WSMTPD - Received: %d bytes from %s:%u",
iCount,
(LPSTR)lpClient->szPeer,
lpClient->saPeer.sin_port);
SetWindowText(hWndDlg, (LPSTR)szTitle);
}
else
{
if((WSAGetLastError()!=WSAENOTCONN)&&
(WSAGetLastError()!=WSAEINPROGRESS))
{
wsprintf((LPSTR)szTitle, "WSMTPD - SOCKET_ERROR #%d from %s:%u",
WSAGetLastError(),
(LPSTR)lpClient->szPeer,
lpClient->saPeer.sin_port);
SetWindowText(hWndDlg, (LPSTR)szTitle);
}
}
}
#endif /* USE_TITLE */
if(iCount==SOCKET_ERROR)
{ // If something was blocking, always try again
return(iCount);
}
if(iCount==0) return(iCount);
iDest=0;
fifoWalker=fifoStop;
while(iDest<iCount)
{
lpBuffer[fifoWalker]=lpLine[iDest];
fifoWalker=(fifoWalker+1)%iMax;
iDest++;
}
lpClient->fifoInputStop=fifoWalker;
return(iCount);
} /* netReceiveData */
#endif /* NET_C */